package cn.tedu.reflection;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*本类用于测试暴力反射*/
public class TestReflect2 {
    /*1,通过暴力反射获取与操作属性*/
    @Test
    public void getFie2() throws Exception {
        //获取字节码对象
        Class<?> clazz = Person.class;
        //获取指定的私有属性,方法参数传入的就是指定的属性名字
        Field field = clazz.getDeclaredField("name");
        //打印查看刚刚获取到的属性对象
        System.out.println(field);
        //根据刚刚获取到的属性对象,进一步查看属性的信息
        System.out.println(field.getType());//class java.lang.String
        System.out.println(field.getType().getName());//java.lang.String

        //设置属性的值
        //1,需要指定到底是给哪个对象的name属性设置值,没有对象就创建对象
        Object p1 = clazz.newInstance();
        //利用反射,触发无参构造创建对象
        /*暴力反射需要设置私有可见的权限!!!*/
        field.setAccessible(true);
        //通过字段对象Filed给刚刚创建好的对象p1设置属性值
        //filed.set(o,n);o是指具体给哪个对象的属性设置值,n是值具体的值是什么
        field.set(p1,"海绵宝宝");
        //filed.get(o);o是只具体查看哪个对象的name属性值
        System.out.println(field.get(p1));


    }
    //定义单元测试方法,利用暴力反射操作person类中的私有属性age
    @Test
    public void getFil3() throws Exception {
        Class<?> clazz = Person.class;
        Field field = clazz.getDeclaredField("age");
        System.out.println(field);
        System.out.println(field.getType().getName());

        Object p2 = clazz.newInstance();
        field.setAccessible(true);
        field.set(p2,666);
        System.out.println(field.get(p2));

    }
    /*2,通过暴力反射获取与使用方法*/
    @Test
    public void getFunction2() throws Exception {
        //获取字节码对象
        Class<?> clazz = Person.class;
        //通过暴力反射获取指定的私有方法
        /*getDeclaredMethods(n,x,y,z...)
        * n:要获取的指定方法的方法名
        * x,y,z...可变参数,是指指定方法的参数类型,注意传入的是字节码对象*/
        Method method = clazz.getDeclaredMethod("save", int.class, String.class);
        //System.out.println(method);
        /*执行私有方法*/
        //没有对象,就通过反射创建对象Person类的对象
       method.setAccessible(true);
        Object p3=clazz.newInstance();
        /*invoke(o,x,y,z...)表示通过反射执行的方法
        * o:要给哪个对象执行上面获取到的save()
        * x,y,z...执行save()时需要传入的参数*/
        method.invoke(p3,999,"感冒灵");
    }
    //巩固练习update
    @Test
    public void getFunction3() throws Exception {
        //获取字节码对象
    Class<?> clazz = Person.class;
    //获取私有方法
        Method method2 = clazz.getDeclaredMethod("update");
        method2.setAccessible(true);
        Object p3=clazz.newInstance();
        method2.invoke(p3);

    }
    //巩固练习add
    @Test
    public void getFunction4() throws Exception {
        Class<?> clazz = Person.class;
        Method method3 = clazz.getDeclaredMethod("add", String.class);
        method3.setAccessible(true);
        Object p4=clazz.newInstance();
        method3.invoke(p4,"感冒灵");


    }
}


